In [ ]:
from data import Lattice, Catalogue
from utils import plotting
import matplotlib.pyplot as plt
from tqdm import tqdm
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import plotly
plotly.offline.init_notebook_mode()

Import unit cell catalogue from PNAS paper by Lumpe, T. S. and Stankovic, T. (2020)

    https://www.pnas.org/doi/10.1073/pnas.2003504118

Catalogue can be downloaded from

    https://doi.org/10.3929/ethz-b-000457598
In [ ]:
cat = Catalogue.from_file('./Unit_Cell_Catalog.txt', indexing=1)
print(cat)
Unit cell catalogue with 17222 entries

Plot a few lattices

In [ ]:
names = cat.names
for i in [0,2]:
    lat = Lattice(**cat.get_unit_cell(names[i]))
    fig = plotting.plotly_unit_cell_3d(lat)
    fig.show()

Lattice ort_Z08.0_E2 below is an example of a faulty unit cell. Beams between nodes 0-3 and 1-2 are intersecting, but no node exists at the intersection

In [ ]:
names = cat.names
lat = Lattice(**cat.get_unit_cell(names[1]))
fig = plotting.plotly_unit_cell_3d(lat)
fig.show()

Collect some statistics about unit cells

In [ ]:
df_data = {}
for name in tqdm(cat.names):
    lat = Lattice(**cat.get_unit_cell(name))
    lat.calculate_edge_lengths(repr='transformed')
    # extract minimum distance between any two nodes
    pos = lat.transformed_node_coordinates
    matrix = pos.reshape((lat.num_nodes, 1, 3)) - pos.reshape((1, lat.num_nodes, 3))
    distances = np.sqrt(np.sum(matrix**2, axis=2))
    distances = distances[np.triu_indices_from(distances, k=1)]
    props = {
        'num_nodes':lat.num_nodes,
        'num_edges':lat.num_edges,
        'min_edge_length':lat.transformed_edge_lengths.min(),
        'mean_edge_length':lat.transformed_edge_lengths.mean(),
        'max_edge_length':lat.transformed_edge_lengths.max(),
        'min_nodal_distance':distances.min()
    }
    df_data.update({name:props})
df = pd.DataFrame(df_data).T
df
100%|██████████| 17222/17222 [00:13<00:00, 1230.69it/s]
Out[ ]:
num_nodes num_edges min_edge_length mean_edge_length max_edge_length min_nodal_distance
cub_Z06.0_E1 8.0 12.0 1.000000 1.000000 1.000000 1.000000
ort_Z08.0_E2 8.0 12.0 0.850750 0.959102 1.026555 0.574490
cub_Z08.0_E3 9.0 8.0 0.866025 0.866025 0.866025 0.866025
hex_Z08.0_E4 8.0 14.0 0.994710 0.996221 1.000000 0.994710
tet_Z04.0_E5 12.0 14.0 0.500000 0.501286 0.503000 0.500000
... ... ... ... ... ... ...
tet_Z03.7_R2726 168.0 212.0 0.025296 0.071671 0.086391 0.025296
cub_Z03.5_R2727 96.0 132.0 0.209300 0.210274 0.211071 0.201681
cub_Z05.0_R2728 60.0 114.0 0.204120 0.249877 0.271540 0.204120
mon_Z05.7_R2729 34.0 45.0 0.000765 0.185892 0.241351 0.000765
cub_Z04.0_R2730 1160.0 2026.0 0.043030 0.084368 0.086736 0.043030

17222 rows × 6 columns

In [ ]:
df.describe()
Out[ ]:
num_nodes num_edges min_edge_length mean_edge_length max_edge_length min_nodal_distance
count 17222.000000 17222.000000 17222.000000 17222.000000 17222.000000 17222.000000
mean 91.254268 113.180989 0.108358 0.234239 0.336314 0.092567
std 101.660985 150.516632 0.109203 0.110778 0.185275 0.098855
min 6.000000 6.000000 0.000003 0.031022 0.039054 0.000000
25% 40.000000 49.000000 0.024573 0.159061 0.204124 0.019207
50% 66.000000 80.000000 0.079647 0.215477 0.293243 0.065931
75% 112.000000 132.000000 0.153460 0.284022 0.420058 0.131330
max 4224.000000 7008.000000 1.000000 1.091532 1.410062 1.000000

Most unit cells have below 200 nodes and edges, but the most complex lattices have thousands. Note that another class of faulty lattices are those which have overlapping nodes -- minimum distance between unique nodes is 0.

In [ ]:
fig = make_subplots(
    rows=2, cols=2, 
    subplot_titles=("Number of nodes", "Number of edges", "Mean edge lengths", "Minimum nodal distance")
)
marker_dict = {'line':{'color':'black', 'width':0.5}}
fig.add_histogram(
    x=df['num_nodes'], name='Nodes', row=1, col=1, 
    marker=marker_dict
)
fig.add_histogram(
    x=df['num_edges'], name='Edges', row=1, col=2, 
    marker=marker_dict, 
)
fig.add_histogram(
    x=df['mean_edge_length'], name='Mean edge length', row=2, col=1, 
    marker=marker_dict, 
)
fig.add_histogram(
    x=df['min_nodal_distance'], name='Minimum distance between nodes', row=2, col=2, 
    marker=marker_dict, 
)
fig.update_layout(xaxis_range=[0,1000])
fig.update_layout(xaxis2_range=[0,1000])
fig.update_layout(title='Unit cell statistics')
fig.update_layout(height=800, width=800, showlegend=False)
fig

Plot unit cells with most nodes/edges. Note that plotly visualisation takes a while

In [ ]:
print(df[df.num_nodes==df.num_nodes.max()])
                 num_nodes  num_edges  min_edge_length  mean_edge_length  \
cub_Z04.0_R2526     4224.0     7008.0         0.000636          0.043935   

                 max_edge_length  min_nodal_distance  
cub_Z04.0_R2526         0.047514            0.000636  
In [ ]:
lat = Lattice(**cat.get_unit_cell('cub_Z04.0_R2526'))
fig = plotting.plotly_unit_cell_3d(lat, node_numbers=False)
fig.show()

Plot a unit cell with overlapping nodes

In [ ]:
print(df.sort_values(by='min_nodal_distance').head(10))
                  num_nodes  num_edges  min_edge_length  mean_edge_length  \
trig_Z05.0_E6999      136.0      143.0         0.000099          0.060219   
trig_Z05.9_E6124      113.0      132.0         0.028911          0.098573   
trig_Z04.8_E6128      128.0      132.0         0.002935          0.061820   
trig_Z05.1_E6998      132.0      143.0         0.022077          0.072384   
trig_Z04.5_E7306      103.0      118.0         0.000003          0.073825   
trig_Z04.4_E9350      116.0      150.0         0.000003          0.096554   
ort_Z05.2_E3240        44.0       56.0         0.000003          0.134318   
ort_Z05.0_E3485        46.0       59.0         0.000003          0.141029   
hex_Z03.5_R2193       124.0      152.0         0.000004          0.066356   
trig_Z05.3_E7254       80.0      121.0         0.000004          0.124587   

                  max_edge_length  min_nodal_distance  
trig_Z05.0_E6999         0.119700            0.000000  
trig_Z05.9_E6124         0.190920            0.000000  
trig_Z04.8_E6128         0.112510            0.000001  
trig_Z05.1_E6998         0.132310            0.000001  
trig_Z04.5_E7306         0.094420            0.000003  
trig_Z04.4_E9350         0.112409            0.000003  
ort_Z05.2_E3240          0.172888            0.000003  
ort_Z05.0_E3485          0.174143            0.000003  
hex_Z03.5_R2193          0.080096            0.000004  
trig_Z05.3_E7254         0.136151            0.000004  

Plot unit cell ort_Z05.2_E3240 which has a relatively low number of nodes. Observing the overlapping node numbers, we see the nodes with overlapping coordinates.

In [ ]:
lat = Lattice(**cat.get_unit_cell('ort_Z05.2_E3240'))
fig = plotting.plotly_unit_cell_3d(lat, repr='transformed')
fig.show()